NEAREST_ND_INTERP
Overview
The NEAREST_ND_INTERP function performs nearest-neighbor interpolation for scattered data in N-dimensional space (where N > 1). Given a set of known data points with associated values, the function estimates values at new query points by assigning each query point the value of its closest known data point.
This implementation uses SciPy’s NearestNDInterpolator, which internally constructs a k-d tree data structure via scipy.spatial.cKDTree for efficient nearest-neighbor lookup. The k-d tree is a space-partitioning binary tree that recursively subdivides the data space along alternating axes, enabling queries in approximately O(\log n) time complexity for well-distributed data, compared to O(n) for brute-force search.
Nearest-neighbor interpolation is particularly useful when:
- Data is irregularly spaced or scattered across multiple dimensions
- Preserving original data values exactly at sample points is required (no smoothing)
- A simple, fast interpolation method is preferred over smoother alternatives
The algorithm assigns the value f(\mathbf{x}_i) to a query point \mathbf{q} where \mathbf{x}_i is the data point minimizing the Euclidean distance:
\mathbf{x}_i = \underset{\mathbf{x} \in X}{\arg\min} \|\mathbf{q} - \mathbf{x}\|_2
Unlike linear or spline interpolation methods, nearest-neighbor interpolation produces a piecewise-constant surface with discontinuities at the boundaries between regions. For smoother results, consider LinearNDInterpolator or CloughTocher2DInterpolator. For data on regular grids, interpn provides a more efficient alternative.
This example function is provided as-is without any representation of accuracy.
Excel Usage
=NEAREST_ND_INTERP(points, values, xi)
points(list[list], required): Data point coordinates (n_points, n_dims)values(list[list], required): Data values (n_points, 1)xi(list[list], required): Query points (n_new_points, n_dims)
Returns (list[list]): A 2D list of interpolated values, or an error message (str) if invalid.
Examples
Example 1: Demo case 1
Inputs:
| points | values | xi | ||
|---|---|---|---|---|
| 0 | 0 | 0 | 0.1 | 0.1 |
| 1 | 0 | 1 | ||
| 0 | 1 | 1 | ||
| 1 | 1 | 2 |
Excel formula:
=NEAREST_ND_INTERP({0,0;1,0;0,1;1,1}, {0;1;1;2}, {0.1,0.1})
Expected output:
| Result |
|---|
| 0 |
Example 2: Demo case 2
Inputs:
| points | values | xi | ||
|---|---|---|---|---|
| 0 | 0 | 0 | 0.1 | 0.1 |
| 1 | 0 | 1 | 0.9 | 0.9 |
| 0 | 1 | 1 | ||
| 1 | 1 | 2 |
Excel formula:
=NEAREST_ND_INTERP({0,0;1,0;0,1;1,1}, {0;1;1;2}, {0.1,0.1;0.9,0.9})
Expected output:
| Result |
|---|
| 0 |
| 2 |
Example 3: Demo case 3
Inputs:
| points | values | xi | ||||
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 10 | 0.2 | 0.1 | 0.1 |
| 1 | 0 | 0 | 20 | |||
| 0 | 1 | 0 | 30 | |||
| 0 | 0 | 1 | 40 |
Excel formula:
=NEAREST_ND_INTERP({0,0,0;1,0,0;0,1,0;0,0,1}, {10;20;30;40}, {0.2,0.1,0.1})
Expected output:
| Result |
|---|
| 10 |
Example 4: Demo case 4
Inputs:
| points | values | xi | ||
|---|---|---|---|---|
| 0 | 0 | 5 | 0.4 | 0.4 |
| 2 | 0 | 10 | 1.6 | 0.4 |
| 0 | 2 | 15 | 1.6 | 1.6 |
| 2 | 2 | 20 |
Excel formula:
=NEAREST_ND_INTERP({0,0;2,0;0,2;2,2}, {5;10;15;20}, {0.4,0.4;1.6,0.4;1.6,1.6})
Expected output:
| Result |
|---|
| 5 |
| 10 |
| 20 |
Python Code
import numpy as np
from scipy.interpolate import NearestNDInterpolator as scipy_NearestNDInterpolator
def nearest_nd_interp(points, values, xi):
"""
Nearest neighbor interpolation in N > 1 dimensions.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.NearestNDInterpolator.html
This example function is provided as-is without any representation of accuracy.
Args:
points (list[list]): Data point coordinates (n_points, n_dims)
values (list[list]): Data values (n_points, 1)
xi (list[list]): Query points (n_new_points, n_dims)
Returns:
list[list]: A 2D list of interpolated values, or an error message (str) if invalid.
"""
def to2d(x):
return [[x]] if not isinstance(x, list) else x
# Normalize inputs to 2D lists
points = to2d(points)
values = to2d(values)
xi = to2d(xi)
# Validate inputs are lists
if not isinstance(points, list) or not isinstance(values, list) or not isinstance(xi, list):
return "Invalid input: points, values, and xi must be 2D lists."
# Validate all elements are lists
if not all(isinstance(row, list) for row in points):
return "Invalid input: points must be a 2D list."
if not all(isinstance(row, list) for row in values):
return "Invalid input: values must be a 2D list."
if not all(isinstance(row, list) for row in xi):
return "Invalid input: xi must be a 2D list."
# Validate non-empty
if len(points) == 0 or len(values) == 0 or len(xi) == 0:
return "Invalid input: points, values, and xi must be non-empty."
# Validate consistent dimensions
if len(points) != len(values):
return "Invalid input: points and values must have the same number of rows."
# Validate all rows have same length
n_dims = len(points[0])
if n_dims == 0:
return "Invalid input: points must have at least one column."
if not all(len(row) == n_dims for row in points):
return "Invalid input: all rows in points must have the same length."
n_dims_xi = len(xi[0])
if n_dims_xi == 0:
return "Invalid input: xi must have at least one column."
if not all(len(row) == n_dims_xi for row in xi):
return "Invalid input: all rows in xi must have the same length."
if n_dims != n_dims_xi:
return "Invalid input: points and xi must have the same number of columns."
# Validate values is single column
if not all(len(row) == 1 for row in values):
return "Invalid input: values must have exactly one column."
# Convert to numpy arrays and validate numeric values
try:
points_arr = np.array(points, dtype=float)
values_arr = np.array(values, dtype=float).flatten()
xi_arr = np.array(xi, dtype=float)
except (ValueError, TypeError):
return "Invalid input: all elements must be numeric."
# Check for NaN or inf values
if np.any(np.isnan(points_arr)) or np.any(np.isinf(points_arr)):
return "Invalid input: points contains non-finite values."
if np.any(np.isnan(values_arr)) or np.any(np.isinf(values_arr)):
return "Invalid input: values contains non-finite values."
if np.any(np.isnan(xi_arr)) or np.any(np.isinf(xi_arr)):
return "Invalid input: xi contains non-finite values."
# Perform interpolation
try:
interp = scipy_NearestNDInterpolator(points_arr, values_arr)
result = interp(xi_arr)
except Exception as exc:
return f"scipy.interpolate.NearestNDInterpolator error: {exc}"
# Validate result
if not isinstance(result, np.ndarray):
return "scipy.interpolate.NearestNDInterpolator error: unexpected result type."
# Check for NaN or inf in result
if np.any(np.isnan(result)) or np.any(np.isinf(result)):
return "scipy.interpolate.NearestNDInterpolator error: result contains non-finite values."
# Convert to 2D list
result_2d = [[float(val)] for val in result]
return result_2d